package org.onion.pattern.event.io.codec;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.SneakyThrows;
import org.onion.pattern.event.io.EventDeserializer;
import org.onion.pattern.event.io.EventSerializer;

public class JacksonEventCodec implements EventSerializer, EventDeserializer {

    public static final JacksonEventCodec INSTANCE = new JacksonEventCodec();

    public static final String       TYPE = "jackson";
    private final       ObjectMapper mapObjectMapper;

    public JacksonEventCodec() {
        this.mapObjectMapper = new ObjectMapper();
        this.init(this.mapObjectMapper);
    }

    @Override
    public String type() {
        return TYPE;
    }

    @SneakyThrows
    @Override
    public <T> T deserialize(byte[] payload, Class<T> clazz) {
        if (payload == null || payload.length <= 0) {
            return null;
        }

        return mapObjectMapper.readValue(payload, clazz);
    }


    @SneakyThrows
    @Override
    public byte[] serialize(Object payload) {
        if (payload == null) {
            return new byte[]{};
        }
        return mapObjectMapper.writeValueAsBytes(payload);
    }

    protected void init(ObjectMapper objectMapper) {
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE).withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        objectMapper.enable(new JsonGenerator.Feature[]{JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN});
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        objectMapper.enable(new MapperFeature[]{MapperFeature.SORT_PROPERTIES_ALPHABETICALLY});
    }

    @Override
    public int getOrder() {
        return 0;
    }

}
